<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    const obj = {
      a1: 'abc',
      a2: {m: 1},
      a3: [123],
      a4: function () {
        console.log('a4')
      }
    }

    /* 
    方式一: 利用JSON对象
    问题: 函数属性会丢失
    原因: json字符串是不能存储函数, 在转为json时就自动丢掉了函数属性
    适用场景: 请求获取的数据都可以
    */
    function cloneDeep(target) {
      return JSON.parse(JSON.stringify(target))
    }
    // const obj2 = cloneDeep(obj)
    // console.log(obj2)


    // 得到类型名称
    function getType(obj) {
      return Object.prototype.toString.call(obj).slice(8, -1)
    }

    /* 
    方式二: 递归遍历拷贝
      只要是对象/数组就需要拷贝其内部数据
      好处: 不会丢失函数属性
    */
    function cloneDeep2(target) {
      const type = getType(target)
      if (type==='Object' || type==='Array') {
        
        let cloneTarget
        if (type==='Object') {
          // 创建拷贝对象
          cloneTarget = {}
          // 遍历对象中所有属性进行拷贝
          Object.keys(target).forEach(key => {
            cloneTarget[key] = cloneDeep2(target[key])  // 对属性值进行递归拷贝
          })
        } else {
          // debugger
          // 创建拷贝数组对象
          cloneTarget = []
          // 遍历数组中所有元素进行拷贝
          target.forEach(item => {
            cloneTarget.push(cloneDeep2(item))  // 对元素进行递归拷贝
          })
        }
        return cloneTarget
      } 
      return target
    }
    const obj2 = cloneDeep2(obj)
    console.log(obj2, obj2.a2===obj.a2, obj2.a4===obj.a4)

  </script>
</body>
</html>